package com.sunwayworld.basemodule.business.result.io;

import com.sunwayworld.baseline.framework.override.LimsExcelHelper;
import com.sunwayworld.basemodule.business.ordertask.bean.LimsOrderTaskBean;
import com.sunwayworld.basemodule.business.result.bean.LimsResultBean;
import com.sunwayworld.basemodule.business.result.bean.LimsRunBean;
import com.sunwayworld.basemodule.business.result.computing.OrderTaskResultComputingEngine;
import com.sunwayworld.basemodule.business.result.service.LimsResultService;
import com.sunwayworld.basemodule.business.result.service.LimsRunService;
import com.sunwayworld.basemodule.common.utils.LimsUtils;
import com.sunwayworld.basemodule.coredata.test.bean.LimsPossibleResultBean;
import com.sunwayworld.basemodule.coredata.test.service.LimsPossibleResultService;
import com.sunwayworld.framework.data.page.Page;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.executor.ExecutorHelper;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.io.file.FilePathDTO;
import com.sunwayworld.framework.io.file.FilePathManager;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.NumberUtils;
import com.sunwayworld.framework.utils.StringUtils;
import com.sunwayworld.module.item.file.bean.CoreFileBean;
import com.sunwayworld.module.item.file.bean.CoreFileImportResultDTO;
import com.sunwayworld.module.item.file.function.CoreFileImportFunction;
import com.sunwayworld.module.item.file.utils.CoreFileUtils;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.FileInputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Component(value = "LimsRunTaskListImportFileFunction")
@GikamBean
public class LimsRunTaskListImportFileFunction implements CoreFileImportFunction {

    @Autowired
    private LimsResultService resultService;

    @Autowired
    private LimsPossibleResultService possibleResultService;

    @Autowired
    private LimsRunService runService;

    public static boolean isValidDate(String str) {
        boolean convertSuccess = true;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        try {
            format.setLenient(false);
            format.parse(str);
        } catch (Exception e) {
            convertSuccess = false;
        }
        return convertSuccess;
    }

    public CoreFileImportResultDTO apply(CoreFileBean coreFileBean) {
        CoreFileImportResultDTO importResultRepresentation = new CoreFileImportResultDTO();
        FilePathDTO fr = CoreFileUtils.toFilePath(coreFileBean);

        XSSFWorkbook workbook = null;

        // 假数据list，用于写错误信息
        List<LimsOrderTaskBean> rowBeans = new ArrayList<>();
        try {
            FileInputStream in = new FileInputStream(FilePathManager.getLocalPath(fr).toString());
            workbook = new XSSFWorkbook(in);

            XSSFSheet sheet = workbook.getSheetAt(0);
            XSSFRow titleRow = sheet.getRow(5);

            String rowRunCode = sheet.getRow(4).getCell(2).getStringCellValue();
            if (StringUtils.isBlank(rowRunCode)) {
                return importResultRepresentation;
            }

            List<LimsRunBean> runBeans = runService.getDao().selectListByOneColumnValue(rowRunCode, "runCode", Arrays.asList("id"));
            if (CollectionUtils.isEmpty(runBeans)) {
                importResultRepresentation.setMessage("任务单编号错误！");
                return importResultRepresentation;
            }

            RestJsonWrapperBean resultWrapperBean = new RestJsonWrapperBean();
            Page<LimsResultBean> page = resultService.selectResultToColumns(runBeans.get(0).getId(), resultWrapperBean);

            int resultColumnNum = page.getTotal();
            int titleRowColumnsNumReal = titleRow.getPhysicalNumberOfCells();
            int fixedColumn = titleRowColumnsNumReal - resultColumnNum;
            // 因为有了那个啥错误信息列，这里都要修改下定位
            for (int i = titleRow.getPhysicalNumberOfCells() - 1; i > 1; i--) {
                XSSFCell cell = titleRow.getCell(i);
                try {
                    String comment = cell.getCellComment().getString().getString();
                    if (!StringUtils.isBlank(comment)) {
                        titleRowColumnsNumReal = i + 1;
                        fixedColumn = titleRowColumnsNumReal - resultColumnNum;
                        break;
                    }
                } catch (Exception e) {
                    continue;
                }
            }

            for (int rowNo = 6; rowNo < sheet.getPhysicalNumberOfRows(); rowNo++) {
                // 每行生成一个用来写错误信息
                LimsOrderTaskBean a = new LimsOrderTaskBean();
                rowBeans.add(a);

                XSSFRow row = sheet.getRow(rowNo);
                XSSFCell sampleCodeCell = row.getCell(1);// 工序任务id
                long orderTaskId = NumberUtils.parseLong(sampleCodeCell.getCellComment().getString().getString());
                a.setId(orderTaskId);

                for (int cellNo = fixedColumn; cellNo < titleRowColumnsNumReal; cellNo++) {
                    XSSFCell cell = row.getCell(cellNo);
                    if (cell == null) {
                        continue;
                    }
                    String analyteId = titleRow.getCell(cellNo).getCellComment().getString().getString();
                    String stringCellValue = LimsUtils.getStringCellValue(row.getCell(cellNo));
                    a.setExt$Item(analyteId, stringCellValue);
                }

            }
            workbook.close();
        } catch (Exception e) {
            e.printStackTrace();
            String message = String.format("%s %s<br/>%s<br/>%s<br/>%s<br/>%s<br/>",
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR"),
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR.PLSCHECK"),
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR.ONE"),
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR.TWO"),
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR.THREE"),
                    I18nHelper.getMessage("RESULTIMPORTFILE.ERROR.MESSAGE.IMPORTERROR.FOUR"));
            throw new InvalidDataException(message);
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (IOException e) {
                    throw new InvalidDataException(I18nHelper.getMessage("MODULE.BUSINESS.RESULT.TIP.RESOLVE_FAILED"));
                }
            }
        }
        // 同步结果
        if (!rowBeans.isEmpty()) {
            // 返还校验结果
            if (rowBeans.stream().anyMatch(i -> !StringUtils.isEmpty(i.getExt$Item("validateimpmsg")))) {
                FilePathDTO filePathDTO = LimsExcelHelper.writeImportFailureListAsExcel(FilePathManager.getLocalPath(fr).toString(), rowBeans, 0, 1, "导入错误信息.xlsx", false);
                importResultRepresentation.setUrl(FilePathManager.getUrl(filePathDTO));
                importResultRepresentation.setMessage("导入失败");
                return importResultRepresentation;
            }
        }

        // 设置结果
        List<Long> orderTaskIdList = rowBeans.stream().map(LimsOrderTaskBean::getId).collect(Collectors.toList());
        List<LimsResultBean> resultBeanList = resultService.getDao().selectListByOneColumnValues(orderTaskIdList, "orderTaskId"
                , Arrays.asList("id", "folderId", "orderTaskId", "analyteId", "analyte", "analType", "editFlag", "writeFlag", "hideFlag"));

        // 过滤掉隐藏的分析项
        resultBeanList = resultBeanList.stream().filter(r -> !StringUtils.equals(r.getHideFlag(), "1")).collect(Collectors.toList());
        Map<Long, List<LimsResultBean>> resultMap = resultBeanList.stream().collect(Collectors.groupingBy(LimsResultBean::getOrderTaskId));
        for (LimsOrderTaskBean orderTaskBean : rowBeans) {
            List<LimsResultBean> resultBeans = resultMap.get(orderTaskBean.getId());
            Map<String, String> map = orderTaskBean.getExt$();
            for (LimsResultBean resultBean : resultBeans) {
                resultBean.setOriginalResult(map.get(resultBean.getAnalyteId().toString()));
            }
        }
        if (resultBeanList.isEmpty()) {
            return importResultRepresentation;
        } else {
            List<LimsPossibleResultBean> possibleResultBeanList = possibleResultService.selectListByFilter(SearchFilter.instance()
                    .match("analyteId", resultBeanList.stream().map(LimsResultBean::getAnalyteId).distinct().collect(Collectors.toList())).filter(MatchPattern.OR));
            Map<Long, List<LimsPossibleResultBean>> possibleResultMap = possibleResultBeanList.stream().collect(Collectors.groupingBy(LimsPossibleResultBean::getAnalyteId));
            resultBeanList.parallelStream().forEach(resultBean -> {
                // 校验分析项填写值是否在备选内容内
                if (!StringUtils.isEmpty(resultBean.getOriginalResult())) {
                    List<LimsPossibleResultBean> possibleResultList = possibleResultMap.get(resultBean.getAnalyteId());
                    if (!CollectionUtils.isEmpty(possibleResultList) && possibleResultList.stream().noneMatch(p ->
                            StringUtils.equals(p.getFinalResult(), resultBean.getOriginalResult()))) {
                        String message = I18nHelper.getMessage("T_CORE_ITEM.SERVICE_NAME") + "【" + resultBean.getAnalyte() + "】" + I18nHelper.getMessage("IMPORT.VALUE.NOT.IN.POSSIBALESELECT") + "；";
                        rowBeans.stream().filter(ot -> ot.getId().equals(resultBean.getOrderTaskId())).findAny().ifPresent(a -> {
                            if (!StringUtils.isBlank(a.getExt$Item("validateimpmsg"))) {
                                a.setExt$Item("validateimpmsg", a.getExt$Item("validateimpmsg").concat(message));
                            } else {
                                a.setExt$Item("validateimpmsg", message);
                            }
                        });
                    }
                } else {
                    if (StringUtils.equals(resultBean.getWriteFlag(), "1")) {
                        if (StringUtils.isBlank(resultBean.getOriginalResult())) {
                            rowBeans.stream().filter(ot -> ot.getId().equals(resultBean.getOrderTaskId())).findAny().ifPresent(a -> {
                                if (!StringUtils.isBlank(a.getExt$Item("validateimpmsg"))) {
                                    a.setExt$Item("validateimpmsg", a.getExt$Item("validateimpmsg").concat("【").concat(resultBean.getAnalyte()).concat("】").concat("分析项必须填写；"));
                                } else {
                                    a.setExt$Item("validateimpmsg", "【".concat(resultBean.getAnalyte()).concat("】").concat("分析项必须填写；"));
                                }
                            });
                        }
                    }
                }
                if ("D".equalsIgnoreCase(resultBean.getAnalType()) && !StringUtils.isEmpty(resultBean.getOriginalResult())) {
                    if (!isValidDate(resultBean.getOriginalResult())) {
                        rowBeans.stream().filter(ot -> ot.getId().equals(resultBean.getOrderTaskId())).findAny().ifPresent(a -> {
                            if (!StringUtils.isBlank(a.getExt$Item("validateimpmsg"))) {
                                a.setExt$Item("validateimpmsg", a.getExt$Item("validateimpmsg").concat("【").concat(resultBean.getAnalyte()).concat("】").concat(I18nHelper.getMessage("RESULT_UPLOAD_DATETIME_CHECK")));
                            } else {
                                a.setExt$Item("validateimpmsg", "【".concat(resultBean.getAnalyte()).concat("】").concat(I18nHelper.getMessage("RESULT_UPLOAD_DATETIME_CHECK")));
                            }
                        });
                    }
                }
                if ("N".equalsIgnoreCase(resultBean.getAnalType()) && !StringUtils.isEmpty(resultBean.getOriginalResult())) {
                    try {
                        Double num = Double.parseDouble(resultBean.getOriginalResult());
                    } catch (Exception e) {
                        rowBeans.stream().filter(ot -> ot.getId().equals(resultBean.getOrderTaskId())).findAny().ifPresent(a -> {
                            if (!StringUtils.isBlank(a.getExt$Item("validateimpmsg"))) {
                                a.setExt$Item("validateimpmsg", a.getExt$Item("validateimpmsg").concat("分析项【").concat(resultBean.getAnalyte()).concat("】应填写数值型结果；"));
                            } else {
                                a.setExt$Item("validateimpmsg", "分析项【".concat(resultBean.getAnalyte()).concat("】应填写数值型结果；"));
                            }
                        });
                    }
                }
            });

            // 返还校验结果
            if (rowBeans.stream().anyMatch(i -> !StringUtils.isEmpty(i.getExt$Item("validateimpmsg")))) {
                FilePathDTO filePathDTO = LimsExcelHelper.writeImportFailureListAsExcel(FilePathManager.getLocalPath(fr).toString(), rowBeans, 5, 6, "导入错误信息.xlsx", false);
                importResultRepresentation.setUrl(FilePathManager.getUrl(filePathDTO));
                importResultRepresentation.setMessage("导入失败");
                return importResultRepresentation;
            }

            resultService.getDao().fastUpdate(resultBeanList, "ORIGINALRESULT");
            //增加公式计算
            List<Long> folderIdList = resultBeanList.stream().map(LimsResultBean::getFolderId).distinct().collect(Collectors.toList());
            ExecutorHelper.submit(() -> OrderTaskResultComputingEngine.getEngine(folderIdList, "com.sunwayworld.baseline.business.ordertask.computing.formula.OrderTaskFormulaRepository").compute());
        }
        return importResultRepresentation;
    }

    @Override
    public boolean test(CoreFileBean coreFile, String service) {
        return true;
    }
}
